home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Software Money Savers / VirtualDub / Source / VirtualDub-1.7.7-src.7z / src / h / vd2 / system / refcount.h < prev    next >
Encoding:
C/C++ Source or Header  |  2006-12-31  |  8.1 KB  |  249 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    System library component
  3. //    Copyright (C) 1998-2004 Avery Lee, All Rights Reserved.
  4. //
  5. //    Beginning with 1.6.0, the VirtualDub system library is licensed
  6. //    differently than the remainder of VirtualDub.  This particular file is
  7. //    thus licensed as follows (the "zlib" license):
  8. //
  9. //    This software is provided 'as-is', without any express or implied
  10. //    warranty.  In no event will the authors be held liable for any
  11. //    damages arising from the use of this software.
  12. //
  13. //    Permission is granted to anyone to use this software for any purpose,
  14. //    including commercial applications, and to alter it and redistribute it
  15. //    freely, subject to the following restrictions:
  16. //
  17. //    1.    The origin of this software must not be misrepresented; you must
  18. //        not claim that you wrote the original software. If you use this
  19. //        software in a product, an acknowledgment in the product
  20. //        documentation would be appreciated but is not required.
  21. //    2.    Altered source versions must be plainly marked as such, and must
  22. //        not be misrepresented as being the original software.
  23. //    3.    This notice may not be removed or altered from any source
  24. //        distribution.
  25.  
  26. #ifndef f_VD2_SYSTEM_REFCOUNT_H
  27. #define f_VD2_SYSTEM_REFCOUNT_H
  28.  
  29. #include <vd2/system/vdtypes.h>
  30. #include <vd2/system/atomic.h>
  31.  
  32. ///////////////////////////////////////////////////////////////////////////
  33. //    IVDRefCount
  34. ///    Base interface for reference-counted objects.
  35. ///
  36. /// Reference counting is a relatively straightforward and simple method
  37. /// of garbage collection. The rules are:
  38. ///
  39. /// 1) Objects increment their reference count on an AddRef() and
  40. ///    decrement it on a Release().
  41. /// 2) Objects destroy themselves when their reference count is dropped
  42. ///    to zero.
  43. /// 3) Clients create references with AddRef() and destroy them with
  44. ///    Release().
  45. ///
  46. /// One way to interact with refcounted objects is to call AddRef()
  47. /// whenever a pointer is created, and Release() when the pointer is
  48. /// nulled or changed.  The vdrefptr<T> template does this automatically.
  49. /// Reference counting may be "combined" between pointers for optimization
  50. /// reasons, such that fewer reference counts are outstanding than actual
  51. /// pointers; this requires weak (non-refcounted) pointers and explicit
  52. /// refcount management.
  53. ///
  54. /// Reference counting has two issues:
  55. ///
  56. /// A) It is expensive.  VirtualDub uses it somewhat sparingly.
  57. ///
  58. /// B) Reference counting cannot cope with cycles.  This issue is
  59. ///    avoided by arranging objects in a clearly ordered tree, such that
  60. ///    no class ever holds a pointer to another object of the same class
  61. ///    or to a parent in the reference hierarchy.  vdrefptr<T> can
  62. ///    implicitly create cycles if you are not careful.
  63. ///
  64. ///    In VirtualDub, reference counting must be multithread safe, so atomic
  65. ///    increment/decrement should be used.  vdrefcounted<T> handles this
  66. ///    automatically for the template type class.
  67. ///
  68. ///    Two final implementation details:
  69. ///
  70. ///    - Little or no code should be executed after the reference count
  71. ///      drops to zero, preferably nothing more than the destructor implicitly
  72. ///      generated by the compiler.  The reason is that otherwise there is the
  73. ///      potential for an object to be resurrected past its final release by
  74. ///      temporarily creating a new reference on the object.
  75. ///
  76. /// - AddRef() and Release() traditionally return the reference count on
  77. ///      the object after increment or decrement, but this is not required.
  78. ///      For Release builds, it is only required that the value for Release()
  79. ///      be zero iff the object is destroyed.  (The same applies for AddRef(),
  80. ///      but since the result of AddRef() is always non-zero, the return of
  81. ///      AddRef() is of no use unless it is the actual count.)
  82. ///
  83. class VDINTERFACE IVDRefCount {
  84. public:
  85.     virtual int AddRef()=0;
  86.     virtual int Release()=0;
  87. };
  88.  
  89. ///////////////////////////////////////////////////////////////////////////
  90. //    vdrefcounted<T>
  91. ///    Implements thread-safe reference counting on top of a base class.
  92. ///
  93. ///    vdrefcounted<T> is used to either add reference counting to a base
  94. ///    class or to implement it on an interface. Use it by deriving your
  95. ///    class from it.
  96. ///
  97. template<class T> class vdrefcounted : public T {
  98. public:
  99.     vdrefcounted() : mRefCount(0) {}
  100.     vdrefcounted(const vdrefcounted<T>& src) : mRefCount(0) {}        // do not copy the refcount
  101.     virtual ~vdrefcounted() {}
  102.  
  103.     vdrefcounted<T>& operator=(const vdrefcounted<T>&) {}            // do not copy the refcount
  104.  
  105.     inline virtual int AddRef() {
  106.         return mRefCount.inc();
  107.     }
  108.  
  109.     inline virtual int Release() {
  110.         if (mRefCount == 1) {        // We are the only reference, so there is no threading issue.  Don't decrement to zero as this can cause double destruction with a temporary addref/release in destruction.
  111.             delete this;
  112.             return 0;
  113.         }
  114.  
  115.         VDASSERT(mRefCount > 1);
  116.  
  117.         return mRefCount.dec();
  118.     }
  119.  
  120. protected:
  121.     VDAtomicInt        mRefCount;
  122. };
  123.  
  124. ///////////////////////////////////////////////////////////////////////////
  125. //    vdrefptr<T>
  126. ///    Reference-counting smart pointer.
  127. ///
  128. ///    Maintains a strong reference on any object that supports AddRef/Release
  129. ///    semantics. This includes any interface including IVDRefCount,
  130. ///    IVDRefUnknown, or the IUnknown interface in Microsoft COM. Because
  131. ///    references are automatically traded as necessary, smart pointers are
  132. ///    very useful for maintaining exception safety.
  133. ///
  134. template<class T> class vdrefptr {
  135. protected:
  136.     T *ptr;
  137.  
  138. public:
  139.     typedef vdrefptr<T> self_type;
  140.     typedef T            element_type;
  141.  
  142.     /// Creates a new smart pointer and obtains a new reference on the
  143.     /// specified object.
  144.     explicit vdrefptr(T *p = 0) : ptr(p) {
  145.         if (p)
  146.             p->AddRef();
  147.     }
  148.  
  149.     /// Clones a smart pointer, duplicating any held reference.
  150.     vdrefptr(const self_type& src) {
  151.         ptr = src.ptr;
  152.         if (ptr)
  153.             ptr->AddRef();
  154.     }
  155.  
  156.     /// Destroys the smart pointer, releasing any held reference.
  157.     ~vdrefptr() {
  158.         if (ptr)
  159.             ptr->Release();
  160.     }
  161.  
  162.     /// Assigns a new object to a smart pointer. Any old object is released
  163.     /// and the new object is addrefed.
  164.     inline self_type& operator=(T *src) {
  165.         if (src)
  166.             src->AddRef();
  167.         if (ptr)
  168.             ptr->Release();
  169.         ptr = src;
  170.         return *this;
  171.     }
  172.  
  173.     /// Assigns a new object to a smart pointer. Any old object is released
  174.     /// and the new object is addrefed.
  175.     inline self_type& operator=(const vdrefptr& src) {
  176.         if (src.ptr)
  177.             src.ptr->AddRef();
  178.         if (ptr)
  179.             ptr->Release();
  180.         ptr = src.ptr;
  181.         return *this;
  182.     }
  183.  
  184.     operator T*() const { return ptr; }
  185.     T& operator*() const { return *ptr; }
  186.     T *operator->() const { return ptr; }
  187.  
  188.     /// Removes any old reference and returns a double-pointer to the nulled
  189.     /// internal pointer. This is useful for passing to IUnknown-derived
  190.     /// interfaces that accept (T **) parameters, like QueryInterface().
  191.     T** operator~() {
  192.         if (ptr) {
  193.             ptr->Release();
  194.             ptr = NULL;
  195.         }
  196.         return &ptr;
  197.     }
  198.  
  199.     /// Removes any held reference.
  200.     inline void clear() {
  201.         if (ptr)
  202.             ptr->Release();
  203.         ptr = NULL;
  204.     }
  205.  
  206.     /// Removes any existing reference and moves a reference from another
  207.     /// smart pointer. The source pointer is cleared afterward.
  208.     inline void from(vdrefptr& src) {
  209.         if (ptr)
  210.             ptr->Release();
  211.         ptr = src.ptr;
  212.         src.ptr = NULL;
  213.     }
  214.  
  215.     /// Removes any existing reference and accepts a reference to a new
  216.     /// object without actually obtaining one. This is useful if someone
  217.     /// has already addrefed an object for you.
  218.     inline void set(T* src) {
  219.         if (ptr)
  220.             ptr->Release();
  221.  
  222.         ptr = src;
  223.     }
  224.  
  225.     /// Returns the held reference and clears the smart pointer without
  226.     /// releasing the reference. This is useful for holding onto a reference
  227.     /// in an exception-safe manner up until the last moment.
  228.     inline T *release() {
  229.         T *p = ptr;
  230.         ptr = NULL;
  231.         return p;
  232.     }
  233. };
  234.  
  235. ///////////////////////////////////////////////////////////////////////////
  236.  
  237. template<class T, class U>
  238. bool VDRefCountObjectFactory(U **pp) {
  239.     T *p = new_nothrow T;
  240.     if (!p)
  241.         return false;
  242.  
  243.     *pp = static_cast<U *>(p);
  244.     p->AddRef();
  245.     return true;
  246. }
  247.  
  248. #endif
  249.